home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / C / Applications / MacWT 0.9 / wt Source / worldfile.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-10-10  |  9.9 KB  |  393 lines  |  [TEXT/CWIE]

  1. /*
  2. **  MacWT -- a 3d game engine for the Macintosh
  3. **  © 1995, Bill Hayden and Nikol Software
  4. **  Free for non-commercial use - address questions to the e-mail address below
  5. **
  6. **  Mail:           afn28988@freenet.ufl.edu (Bill Hayden)
  7. **    MacWT FTP site: ftp.circa.ufl.edu/pub/software/ufmug/mirrors/LocalSW/Hayden/
  8. **  WWW Page:       http://grove.ufl.edu:80/~nikolsw
  9. **
  10. **    All of the above addresses are due to changes sometime in 1996, so stay tuned
  11. **
  12. **  based on wt, by Chris Laurel
  13. **
  14. **  This program is distributed in the hope that it will be useful,
  15. **  but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  17. */
  18.  
  19.  
  20. #include <stdio.h>
  21. #include <string.h>
  22. #include <stdlib.h>
  23. #include <ctype.h>
  24. #include <limits.h>
  25. #include <math.h>
  26.  
  27. #include "wt.h"
  28. #include "error.h"
  29. #include "fixed.h"
  30. #include "wtmem.h"
  31. #include "list.h"
  32. #include "table.h"
  33. #include "framebuf.h"
  34. #include "texture.h"
  35. #include "world.h"
  36. #include "view.h"
  37. #include "object.h"
  38. #include "worldfile.h"
  39.  
  40.  
  41. #define TEXTURE_NAME_MAX_LENGTH 32
  42. #define STRING_TOKEN_MAX_LENGTH 256
  43.  
  44. #define IS_STRING_TOKEN_CHAR(c) (isalpha(c) || isdigit(c) || \
  45.                  (c) == '/' || c == '.' || c == '_')
  46. #define COMMENT_CHAR ';'
  47.  
  48. typedef struct {
  49.      char name[TEXTURE_NAME_MAX_LENGTH + 1];
  50.      int index;
  51. } Texture_node;
  52.  
  53. typedef enum {
  54.      Token_string,
  55.      Token_real,
  56.      Token_integer,
  57.      Token_EOF
  58. } Token_type;
  59.  
  60.  
  61. static void parse_world(FILE *fp, World *w);
  62. static void parse_vertex(FILE *fp, World *w);
  63. static void parse_wall(FILE *fp, World *w);
  64. static void parse_region(FILE *fp, World *w);
  65. static void parse_texture(FILE *fp, World *w);
  66. static void parse_start(FILE *fp);
  67. static int get_texture_index(char *name);
  68. static Boolean find_list_name(List *l, void *data);
  69. static Token_type get_string_token(FILE *fp, char *tokenbuf);
  70. static Token_type get_real_token(FILE *fp, fixed *f);
  71. static Token_type get_integer_token(FILE *fp, int *i);
  72. static int skip_whitespace(FILE *fp);
  73. static void parse_error(char *message);
  74.  
  75. static List *texture_list;
  76. static int line_number;
  77.  
  78.  
  79. World *read_world_file(FILE *fp)
  80. {
  81.      World *w;
  82.  
  83.      w = new_world();
  84.      texture_list = new_list();
  85.      parse_world(fp, w);
  86.      delete_list(texture_list);
  87.  
  88.      return w;
  89. }
  90.  
  91.  
  92. static void parse_world(FILE *fp, World *w)
  93. {
  94.      char tokenbuf[STRING_TOKEN_MAX_LENGTH];
  95.  
  96.      while (get_string_token(fp, tokenbuf) != Token_EOF) {
  97.       if (strcmp(tokenbuf, "texture") == 0)
  98.            parse_texture(fp, w);
  99.       else if (strcmp(tokenbuf, "wall") == 0)
  100.            parse_wall(fp, w);
  101.       else if (strcmp(tokenbuf, "region") == 0)
  102.            parse_region(fp, w);
  103.       else if (strcmp(tokenbuf, "vertex") == 0)
  104.            parse_vertex(fp, w);
  105.       else if (strcmp(tokenbuf, "start") == 0)
  106.            parse_start(fp);
  107.       else
  108.            parse_error("unknown structure type");
  109.      }
  110. }
  111.  
  112.  
  113. static void parse_vertex(FILE *fp, World *w)
  114. {
  115.     extern Bounds WorldBounds;
  116.     Vertex v;
  117.  
  118.  
  119.     if (get_real_token(fp, &v.x) != Token_real)
  120.         parse_error("number expected");
  121.     if (get_real_token(fp, &v.y) != Token_real)
  122.         parse_error("number expected");
  123.  
  124.     add_vertex(w, &v);
  125.      
  126.     if (FIXED_TO_FLOAT(v.x) < WorldBounds.left) WorldBounds.left = FIXED_TO_FLOAT(v.x);
  127.     if (FIXED_TO_FLOAT(v.x) > WorldBounds.right) WorldBounds.right = FIXED_TO_FLOAT(v.x);
  128.     if (FIXED_TO_FLOAT(v.y) < WorldBounds.top) WorldBounds.top = FIXED_TO_FLOAT(v.y);
  129.     if (FIXED_TO_FLOAT(v.y) > WorldBounds.bottom) WorldBounds.bottom = FIXED_TO_FLOAT(v.y);
  130. }
  131.  
  132.  
  133. static void parse_region(FILE *fp, World *w)
  134. {
  135.     char texture_name[STRING_TOKEN_MAX_LENGTH];
  136.     short texture_index;
  137.     Region r;
  138.  
  139.     if (get_real_token(fp, &r.floor) != Token_real)
  140.         parse_error("number expected");
  141.     if (get_real_token(fp, &r.ceiling) != Token_real)
  142.         parse_error("number expected");
  143.  
  144.     /* floor texture */
  145.     if (get_string_token(fp, texture_name) != Token_string)
  146.         parse_error("texture name expected");
  147.     texture_index = get_texture_index(texture_name);
  148.     if (texture_index < 0 || texture_index > TABLE_SIZE(w->textures))
  149.         parse_error("non-existent texture");
  150.     else
  151.         r.floor_tex = WORLD_TEXTURE(w, texture_index);
  152.  
  153.     /* ceiling texture */
  154.     if (get_string_token(fp, texture_name) != Token_string)
  155.         parse_error("texture name expected");
  156.     if (strcmp(texture_name, "sky") == 0)
  157.         r.ceiling_tex = NULL;
  158.     else
  159.         {
  160.         texture_index = get_texture_index(texture_name);
  161.         if (texture_index < 0 || texture_index > TABLE_SIZE(w->textures))
  162.             parse_error("non-existent texture");
  163.         else
  164.             r.ceiling_tex = WORLD_TEXTURE(w, texture_index);
  165.         }
  166.  
  167.     add_region(w, &r);
  168. }
  169.  
  170.  
  171. static void parse_wall(FILE *fp, World *w)
  172. {
  173.     Wall wall;
  174.     char texture_name[STRING_TOKEN_MAX_LENGTH];
  175.     short texture_index;
  176.     int front_region, back_region;
  177.     int vertex1, vertex2;
  178.     fixed wall_length;
  179.  
  180.  
  181.     /* vertices */
  182.     if (get_integer_token(fp, &vertex1) != Token_integer)
  183.         parse_error("integer expected");
  184.     if (get_integer_token(fp, &vertex2) != Token_integer)
  185.         parse_error("integer expected");
  186.     if (vertex1 < 0 || vertex1 > TABLE_SIZE(w->vertices))
  187.         parse_error("invalid vertex number");
  188.     if (vertex2 < 0 || vertex2 > TABLE_SIZE(w->vertices))
  189.         parse_error("invalid vertex number");
  190.     wall.vertex1 = &WORLD_VERTEX(w, vertex1);
  191.     wall.vertex2 = &WORLD_VERTEX(w, vertex2);
  192.  
  193.      /* texture */
  194.     if (get_string_token(fp, texture_name) != Token_string)
  195.         parse_error("texture name expected");
  196.     texture_index = get_texture_index(texture_name);
  197.     if (texture_index < 0 || texture_index > TABLE_SIZE(w->textures))
  198.         parse_error("non-existent texture");
  199.     else
  200.         wall.surface_texture = WORLD_TEXTURE(w, texture_index);
  201.  
  202.     wall.sky = (strcmp(texture_name, "sky") == 0);
  203.  
  204.     /* front and back regions */
  205.     if (get_integer_token(fp, &front_region) != Token_integer)
  206.         fatal_error("non-existent region");
  207.     if (get_integer_token(fp, &back_region) != Token_integer)
  208.         fatal_error("non-existent region");
  209.     if (front_region < 0 || front_region > TABLE_SIZE(w->regions))
  210.         fatal_error("non-existent region");
  211.     if (back_region < 0 || back_region > TABLE_SIZE(w->regions))
  212.         fatal_error("non-existent region");
  213.     wall.front = &WORLD_REGION(w, front_region);
  214.     wall.back = &WORLD_REGION(w, back_region);
  215.  
  216.      /* Texture phase and scale.  This code is somewhat more complicated than
  217.      **   you'd expect, since the texture scale must be normalized to the
  218.      **   wall length.
  219.      */
  220.     if (get_real_token(fp, &wall.xscale) != Token_real)
  221.         parse_error("number expected");
  222.     if (get_real_token(fp, &wall.yscale) != Token_real)
  223.         parse_error("number expected");
  224.     if (get_real_token(fp, &wall.xphase) != Token_real)
  225.         parse_error("number expected");
  226.     if (get_real_token(fp, &wall.yphase) != Token_real)
  227.         parse_error("number expected");
  228.       
  229.     wall_length = FLOAT_TO_FIXED(sqrt(FIXED_TO_FLOAT(wall.vertex2->x - wall.vertex1->x) *
  230.                   FIXED_TO_FLOAT(wall.vertex2->x - wall.vertex1->x) +
  231.                   FIXED_TO_FLOAT(wall.vertex2->y - wall.vertex1->y) *
  232.                   FIXED_TO_FLOAT(wall.vertex2->y - wall.vertex1->y)));
  233.     wall.yscale = fixmul(wall.yscale, INT_TO_FIXED(wall.surface_texture->height));
  234.     wall.xscale = fixmul(fixmul(wall.xscale, INT_TO_FIXED(wall.surface_texture->width)),
  235.                             wall_length);
  236.     wall.xphase = FIXED_SCALE(wall.xphase, wall.surface_texture->width);
  237.     wall.yphase = FIXED_SCALE(wall.yphase, wall.surface_texture->height);
  238.  
  239.     add_wall(w, &wall);
  240. }
  241.  
  242.  
  243. static void parse_texture(FILE *fp, World *w)
  244. {
  245.     char texture_name[STRING_TOKEN_MAX_LENGTH];
  246.     char filename[STRING_TOKEN_MAX_LENGTH];
  247.     char texture_path[PATH_MAX + STRING_TOKEN_MAX_LENGTH];
  248.     Texture *t;
  249.     Texture_node *tn;
  250.  
  251.  
  252.     if (get_string_token(fp, texture_name) != Token_string)
  253.         parse_error("texture name expected");
  254.     if (strlen(texture_name) >= TEXTURE_NAME_MAX_LENGTH)
  255.         parse_error("texture name too long");
  256.  
  257.     if (get_string_token(fp, filename) != Token_string)
  258.         parse_error("texture file name expected");
  259.  
  260.     sprintf(texture_path, "%s:%s", TEXTURE_PATH, filename);
  261.     t = read_texture_file(texture_path);
  262.  
  263.     tn = (Texture_node *)wtmalloc(sizeof(Texture_node));
  264.     strcpy(tn->name, texture_name);
  265.     tn->index = TABLE_SIZE(w->textures);
  266.  
  267.     add_node(texture_list, tn);
  268.     add_texture(w, t);
  269. }
  270.          
  271.  
  272. static void parse_start(FILE *fp)
  273. {
  274.     extern fixed start_x, start_y;
  275.     fixed x, y;
  276.  
  277.     if (get_real_token(fp, &x) != Token_real)
  278.         parse_error("number expected");
  279.     if (get_real_token(fp, &y) != Token_real)
  280.         parse_error("number expected");
  281.  
  282.     start_x = x;
  283.     start_y = y;
  284. }
  285.  
  286.  
  287. static int get_texture_index(char *name)
  288. {
  289.     List *l;
  290.  
  291.     l = scan_list(texture_list, name, find_list_name);
  292.     if (l == NULL)
  293.         fatal_error("get_texture_index:  could not find %s\n", name);
  294.     else
  295.         return LIST_NODE(l, Texture_node *)->index;
  296. }
  297.  
  298.  
  299. static Boolean find_list_name(List *l, void *data)
  300. {
  301.     if (strcmp((char *) data, LIST_NODE(l, Texture_node *)->name) == 0)
  302.         return TRUE;
  303.     else
  304.         return FALSE;
  305. }
  306.  
  307.      
  308. static Token_type get_string_token(FILE *fp, char *tokenbuf)
  309. {
  310.     long    length = 0;
  311.     int        c;
  312.  
  313.     c = skip_whitespace(fp);
  314.     if (c == EOF)
  315.         return Token_EOF;
  316.  
  317.     while (c != EOF && IS_STRING_TOKEN_CHAR(c))
  318.         {
  319.         if (length >= STRING_TOKEN_MAX_LENGTH - 1)
  320.             parse_error("string too long");
  321.  
  322.         tokenbuf[length] = c;
  323.         length++;
  324.  
  325.         c = getc(fp);
  326.         }
  327.  
  328.     ungetc(c, fp);
  329.     tokenbuf[length] = '\0';
  330.  
  331.     return Token_string;
  332. }
  333.  
  334.  
  335. static Token_type get_real_token(FILE *fp, fixed *f)
  336. {
  337.      double d;
  338.      int c;
  339.  
  340.      c = skip_whitespace(fp);
  341.      if (c == EOF)
  342.       return Token_EOF;
  343.  
  344.      ungetc(c, fp);
  345.      if (fscanf(fp, "%lf", &d) != 1)
  346.       parse_error("numeric constant expected");
  347.  
  348.      *f = FLOAT_TO_FIXED(d);
  349.  
  350.      return Token_real;
  351. }
  352.  
  353.  
  354. static Token_type get_integer_token(FILE *fp, int *i)
  355. {
  356.      int c;
  357.  
  358.      c = skip_whitespace(fp);
  359.      if (c == EOF)
  360.       return Token_EOF;
  361.  
  362.      ungetc(c, fp);
  363.      if (fscanf(fp, "%d", i) != 1)
  364.       parse_error("integer constant expected");
  365.  
  366.      return Token_integer;
  367. }
  368.  
  369.       
  370. static int skip_whitespace(FILE *fp)
  371. {
  372.      int c = getc(fp);
  373.  
  374.      while (c == ' ' || c == '\t' || c == '\n' || c == COMMENT_CHAR) {
  375.       if (c == COMMENT_CHAR) {
  376.            while (c != EOF && c != '\n')
  377.             c = getc(fp);
  378.       }
  379.  
  380.       if (c == '\n')
  381.            line_number++;
  382.       c = getc(fp);
  383.      }
  384.  
  385.      return c;
  386. }
  387.  
  388.  
  389. static void parse_error(char *message)
  390. {
  391.     fatal_error("Error in world file (line %d):  %s\n", line_number, message);
  392. }
  393.